﻿using NPOI.OpenXmlFormats.Wordprocessing;
using NPOI.XWPF.UserModel;

namespace DB2WORD.Logics
{
    public static class NpoiWordHelper
    {
        private static class Cache<T>
        {
            private static readonly Dictionary<object, T> dic = new Dictionary<object, T>();
            public static T Get(object obj, Func<T> creator)
            {
                if(dic.TryGetValue(obj, out T v))
                {
                    return v;
                }
                v = creator();
                dic[obj] = v;
                return v;
            }
        }

        #region XWPFDocument
        public static XWPFDocument WithEmptyParagraph(this XWPFDocument document, int count = 1)
        {
            XWPFParagraph paragraph = document.CreateParagraph();
            for(int i = 0; i < count; i++)
            {
                paragraph.CreateRun();
            }
            document.SetParagraph(paragraph, 0);
            return document;
        }
        #endregion

        #region XWPFTable   

        public static XWPFTable WithColumnWidths(this XWPFTable table, params ulong[] widths)
        {
            for(int i = 0; i < widths.Length; i++)
            {
                table.SetColumnWidth(i, widths[i]);
            }
            return table;
        }

        public static XWPFTable WithParagraph(this XWPFTable table, int row, int col, XWPFParagraph paragraph, ST_VerticalJc verticalAlignment = ST_VerticalJc.center)
        {
            table.GetRow(row).GetCell(col).SetParagraph(paragraph);
            var valign = Cache<CT_VerticalJc>.Get(verticalAlignment, () => new CT_VerticalJc() { val = ST_VerticalJc.center });
            table.GetRow(row).GetCell(col).GetCTTc().AddNewTcPr().vAlign = valign;
            return table;
        }

        #endregion

        #region XWPFParagraph
        public static XWPFParagraph WithTitleLevel(this XWPFParagraph paragraph, string styleID)
        {
            paragraph.Style = styleID;
            return paragraph;
        }

        #endregion

        #region XWPFRun
        public static XWPFRun WithText(this XWPFRun run, string text)
        {
            run.SetText(text);
            return run;
        }
        public static XWPFRun WithFontSize(this XWPFRun run, int fontSize)
        {
            if(fontSize > 1)
            {
                run.FontSize = fontSize;
            }
            return run;
        }
        public static XWPFRun WithBold(this XWPFRun run, bool isBold = true)
        {
            run.IsBold = isBold;
            return run;
        }
        public static XWPFRun WithItalic(this XWPFRun run, bool isItalic = true)
        {
            run.IsItalic = isItalic;
            return run;
        }
        public static XWPFRun WithForeColor(this XWPFRun run, string? foreColor)
        {
            if(!string.IsNullOrWhiteSpace(foreColor))
            {
                run.SetColor(foreColor);
            }
            return run;
        }
        public static XWPFRun WithFontFamily(this XWPFRun run, string? fontFamily)
        {
            if(!string.IsNullOrWhiteSpace(fontFamily))
            {
                run.SetFontFamily(fontFamily, FontCharRange.None);
            }
            return run;
        }

        #endregion

        /// <summary>
        /// 创建word文档中的段落对象和设置段落文本的基本样式（字体大小，字体，字体颜色，字体对齐位置）
        /// </summary>
        /// <param name="document">document文档对象</param>
        /// <param name="fillContent">段落第一个文本对象填充的内容</param>
        /// <param name="isBold">是否加粗</param>
        /// <param name="fontSize">字体大小</param>
        /// <param name="fontFamily">字体</param>
        /// <param name="paragraphAlign">段落排列（左对齐，居中，右对齐）</param>
        /// <param name="secondFillContent">第二次声明的文本对象填充的内容，样式与第一次的一致</param>
        /// <param name="fontColor">字体颜色--十六进制</param>
        /// <param name="isItalic">是否设置斜体（字体倾斜）</param>
        /// <returns></returns>
        public static XWPFParagraph CreateParagraph(this XWPFDocument document, string fillContent, int fontSize, ParagraphAlignment paragraphAlign = ParagraphAlignment.LEFT, TextAlignment verticalAlignment = TextAlignment.CENTER, string? fontFamily = "宋体", string fontColor = "000000", bool isBold = false, bool isItalic = false)
        {
            XWPFParagraph paragraph = document.CreateParagraph();//创建段落对象
            paragraph.Alignment = paragraphAlign;//文字显示位置,段落排列（左对齐，居中，右对齐）
            paragraph.VerticalAlignment = verticalAlignment;

            XWPFRun xwpfRun = paragraph.CreateRun()
                .WithText(fillContent)
                .WithFontSize(fontSize)
                .WithFontFamily(fontFamily)
                .WithForeColor(fontColor)
                .WithBold(isBold)
                .WithItalic(isItalic);

            return paragraph;
        }


        /// <summary> 
        /// 创建Word文档中表格段落实例和设置表格段落文本的基本样式（字体大小，字体，字体颜色，字体对齐位置）
        /// </summary> 
        /// <param name="document">document文档对象</param> 
        /// <param name="table">表格对象</param> 
        /// <param name="fillContent">要填充的文字</param> 
        /// <param name="paragraphAlign">段落排列（左对齐，居中，右对齐）</param>
        /// <param name="textPosition">设置文本位置（设置两行之间的行间,从而实现表格文字垂直居中的效果），从而实现table的高度设置效果 </param>
        /// <param name="isBold">是否加粗（true加粗，false不加粗）</param>
        /// <param name="fontSize">字体大小</param>
        /// <param name="fontColor">字体颜色--十六进制</param>
        /// <param name="isItalic">是否设置斜体（字体倾斜）</param>
        /// <returns></returns> 
        public static XWPFParagraph CreateParagraph(this XWPFTable table, string fillContent, ParagraphAlignment paragraphAlign = ParagraphAlignment.LEFT, bool isBold = false, int fontSize = 9, string? fontFamily = "宋体", string fontColor = "000000", bool isItalic = false)
        {
            var para = new CT_P();
            para.AddNewPPr().AddNewTextAlignment();

            XWPFParagraph paragraph = new XWPFParagraph(para, table.Body);
            paragraph.Alignment = paragraphAlign;
            //paragraph.FontAlignment =Convert.ToInt32(ParagraphAlignment.CENTER);//字体在单元格内显示位置与 paragraph.Alignment效果相似

            XWPFRun xwpfRun = paragraph.CreateRun()
               .WithText(fillContent)
               .WithFontSize(fontSize)
               .WithFontFamily(fontFamily)
               .WithForeColor(fontColor)
               .WithBold(isBold)
               .WithItalic(isItalic);

            return paragraph;
        }

        /// <summary>
        /// 创建Word文档中表格段落实例和设置表格段落文本的基本样式(字体大小，字体，字体颜色，字体对齐位置)
        /// document文档对象
        /// 表格对象
        /// 要填充的文字
        /// 段落排列(左对齐，居中，右对齐)
        /// 设置文本位置(设置两行之间的行间)，从而实现table的高度设置效果 
        /// 是否加粗(true加粗，false不加粗)
        /// 字体大小
        /// </summary>
        /// <param name="table"></param>
        /// <param name="fillContent"></param>
        /// <param name="paragraphAlign"></param>
        /// <param name="rowsHeight"></param>
        /// <param name="isBold"></param>
        /// <param name="fontSize"></param>
        /// <returns></returns>
        public static XWPFParagraph CreateParagraph(this XWPFTable table, List<string> fillContent, ParagraphAlignment paragraphAlign = ParagraphAlignment.LEFT, bool isBold = false, int fontSize = 9, string fontColor = "000000", bool isItalic = false)
        {
            var para = new CT_P();

            XWPFParagraph paragraph = new XWPFParagraph(para, table.Body);//创建表格中的段落对象

            paragraph.Alignment = paragraphAlign;//文字显示位置,段落排列(左对齐，居中，右对齐)
            paragraph.VerticalAlignment = TextAlignment.CENTER;

            XWPFRun xwpfRun = paragraph.CreateRun();//创建段落文本对象
            int index = 0;
            foreach(var item in fillContent)
            {
                if(index > 0)
                {
                    xwpfRun.AddBreak(BreakType.TEXTWRAPPING);//换行TEXTWRAPPING
                    //xwpfRun.AddTab();
                }

                xwpfRun.SetText(item, index);
                index++;
            }
            xwpfRun.FontSize = fontSize;//字体大小

            xwpfRun.SetColor(fontColor);//设置字体颜色--十六进制
            xwpfRun.IsItalic = isItalic;//是否设置斜体（字体倾斜）
            xwpfRun.IsBold = isBold;//是否加粗

            xwpfRun.SetFontFamily("宋体", FontCharRange.None);//设置字体(如：微软雅黑,华文楷体,宋体)

            //xwpfRun.SetTextPosition(rowsHeight);//设置文本位置(设置两行之间的行间)，从而实现table的高度设置效果

            return paragraph;

        }


        /// <summary>
        /// 合并列
        /// </summary>
        /// <param name="table"></param>
        /// <param name="col"></param>
        /// <param name="fromRow"></param>
        /// <param name="toRow"></param>
        public static XWPFTable MergeVertically(this XWPFTable table, int col, int fromRow, int toRow)
        {
            for(int rowIndex = fromRow; rowIndex <= toRow; rowIndex++)
            {
                XWPFTableCell cell = table.GetRow(rowIndex).GetCell(col);
                if(rowIndex == fromRow)
                {
                    cell.GetCTTc().AddNewTcPr().AddNewVMerge().val = ST_Merge.restart;
                }
                else
                {
                    cell.GetCTTc().AddNewTcPr().AddNewVMerge().val = ST_Merge.@continue;
                }
            }
            //合并后垂直居中
            table.GetRow(fromRow).GetCell(col).SetVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
            return table;
        }
        /// <summary>
        /// 合并行
        /// </summary>
        /// <param name="table"></param>
        /// <param name="row"></param>
        /// <param name="fromCell"></param>
        /// <param name="toCell"></param>
        public static XWPFTable MergeHorizontal(this XWPFTable table, int row, int fromCell, int toCell)
        {
            for(int cellIndex = fromCell; cellIndex <= toCell; cellIndex++)
            {
                XWPFTableCell cell = table.GetRow(row).GetCell(cellIndex);
                if(cellIndex == fromCell)
                {
                    cell.GetCTTc().AddNewTcPr().AddNewHMerge().val = ST_Merge.restart;
                }
                else
                {
                    cell.GetCTTc().AddNewTcPr().AddNewHMerge().val = ST_Merge.@continue;
                }
            }
            //合并后垂直居中
            table.GetRow(row).GetCell(fromCell).SetVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
            return table;
        }


        public static XWPFDocument SetPageHeader(this XWPFDocument document, string header)
        {
            if(document.Document.body.sectPr == null)
            {
                document.Document.body.sectPr = new CT_SectPr();
            }
            CT_SectPr m_SectPr = document.Document.body.sectPr;
            //创建页眉
            CT_Hdr m_Hdr = new CT_Hdr();
            CT_P m_P = m_Hdr.AddNewP();
            m_P.AddNewR().AddNewT().Value = header;
            m_P.AddNewPPr().AddNewJc().val = ST_Jc.center;// 页眉居中
                                                          //创建页眉关系（headern.xml）
            XWPFHeader m_h = (XWPFHeader)document.CreateRelationship(XWPFRelation.HEADER, XWPFFactory.GetInstance(), document.HeaderList.Count + 1);
            //document.CreateFootnotes();
            //设置页眉
            m_h.SetHeaderFooter(m_Hdr);
            CT_HdrFtrRef m_HdrFtr = m_SectPr.AddNewHeaderReference();
            m_HdrFtr.type = ST_HdrFtr.@default;
            m_HdrFtr.id = m_h.GetPackageRelationship().Id;
            return document;
        }


        public static XWPFDocument SetPageFooter(this XWPFDocument document, string footer)
        {
            if(document.Document.body.sectPr == null)
            {
                document.Document.body.sectPr = new CT_SectPr();
            }
            CT_SectPr m_SectPr = document.Document.body.sectPr;

            //创建页脚
            CT_Ftr m_ftr = new CT_Ftr();
            CT_P m_fP = m_ftr.AddNewP();
            m_fP.AddNewR().AddNewT().Value = footer;
            m_fP.AddNewPPr().AddNewJc().val = ST_Jc.center;// 页眉居中
                                                           //创建页脚关系（footern.xml）
            XWPFFooter m_f = (XWPFFooter)document.CreateRelationship(XWPFRelation.FOOTER, XWPFFactory.GetInstance(), document.FooterList.Count + 1);
            //设置页脚
            m_f.SetHeaderFooter(m_ftr);
            CT_HdrFtrRef m_HdrFtr = m_SectPr.AddNewFooterReference();
            m_HdrFtr.type = ST_HdrFtr.@default;
            m_HdrFtr.id = m_f.GetPackageRelationship().Id;
            return document;
        }

        public static XWPFParagraph CreateImage(this XWPFDocument document, string imageFilePath)
        {
            XWPFParagraph paragraph = document.CreateParagraph();
            paragraph.Alignment = ParagraphAlignment.CENTER;
            using(FileStream gfs = new FileStream(imageFilePath, FileMode.Open, FileAccess.Read))
            {
                XWPFRun xwpfRun = paragraph.CreateRun();
                xwpfRun.AddPicture(gfs, (int)PictureType.PNG, "1.png", (int)(330 * 9525), (int)(100 * 9525));
            }
            return paragraph;
        }

        public static XWPFDocument WithNewPage(this XWPFDocument document)
        {
            XWPFParagraph xWPFParagraph = document.CreateParagraph();
            xWPFParagraph.CreateRun().AddBreak();
            return document;
        }
    }
}
